package com.xbn.xbnmall.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.xbn.common.exception.NoStockException;
import com.xbn.common.to.SkuHasStockVo;
import com.xbn.common.utils.R;
import com.xbn.common.vo.MemberRespVo;
import com.xbn.xbnmall.order.constant.OrderConstant;
import com.xbn.xbnmall.order.dao.OrderItemDao;
import com.xbn.xbnmall.order.entity.OrderItemEntity;
import com.xbn.xbnmall.order.enume.OrderStatusEnum;
import com.xbn.xbnmall.order.feign.CartFeignService;
import com.xbn.xbnmall.order.feign.MemberFeignService;
import com.xbn.xbnmall.order.feign.ProductFeignService;
import com.xbn.xbnmall.order.feign.WmsFeignService;
import com.xbn.xbnmall.order.interceptor.LoginUserInterceptor;
import com.xbn.xbnmall.order.service.OrderItemService;
import com.xbn.xbnmall.order.to.MemberReceiveAddressTo;
import com.xbn.xbnmall.order.to.OrderCreateTo;
import com.xbn.xbnmall.order.vo.*;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xbn.common.utils.PageUtils;
import com.xbn.common.utils.Query;

import com.xbn.xbnmall.order.dao.OrderDao;
import com.xbn.xbnmall.order.entity.OrderEntity;
import com.xbn.xbnmall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    OrderItemService orderItemService;
    @Autowired
    MemberFeignService memberFeignService;
    @Autowired
    CartFeignService cartFeignService;
    @Autowired
    ThreadPoolExecutor executor;
    @Autowired
    WmsFeignService wmsFeignService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    ProductFeignService productFeignService;
    private ThreadLocal<OrderSubmitVo> confirmVoThreadLocal=new ThreadLocal<>();
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    /*
    * 订单确认页添加需要的信息
    * */
    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
   OrderConfirmVo orderConfirmVo=new OrderConfirmVo();
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();

        //将请求中的信息带给异步任务的线程
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

        //远程查询用户的所有收货地址列表
        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
            //设置主线程的请求参数到本线程
            System.out.println("查询用户地址线程号："+Thread.currentThread().getId());
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressVo> address = memberFeignService.getAddress(memberRespVo.getId());
            orderConfirmVo.setAddress(address);
        }, executor);

        //远程查询购物车所有选中的购物项
        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            //设置主线程的请求参数到本线程
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVo> currentUserCartItems = cartFeignService.getCurrentUserCartItems();

            orderConfirmVo.setItems(currentUserCartItems);
        }, executor)
                //查询库存信息
                .thenRunAsync(()->{
                    List<OrderItemVo> items = orderConfirmVo.getItems();
                    List<Long> collect = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
                    R skusHasStockR = wmsFeignService.getSkusHasStock(collect);
                    List<SkuHasStockVo> data = skusHasStockR.getData("data", new TypeReference<List<SkuHasStockVo>>() {});
                    if(data!=null&&data.size()>0)
                    {
                        Map<Long, Boolean> collect1 = data.stream().collect
                                (Collectors.toMap(SkuHasStockVo::getSkuId, SkuHasStockVo::getHasStock));
                        orderConfirmVo.setStocks(collect1);
                    }
                },executor);
                ;

        //远程用户积分
        orderConfirmVo.setIntegration(memberRespVo.getIntegration());
        CompletableFuture.allOf(addressFuture,cartFuture).get();
        //防重令牌，避免用户多次提交订单
        String orderToken = UUID.randomUUID().toString().replaceAll("-", "");
        //给页面添加令牌
      orderConfirmVo.setOrderToken(orderToken);
        //在redis中添加一份令牌
        stringRedisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX+
                memberRespVo.getId(),orderToken,30, TimeUnit.MINUTES);
        return orderConfirmVo;
    }
   // @GlobalTransactional
    @Transactional
    @Override
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo vo) {
        confirmVoThreadLocal.set(vo);
        SubmitOrderResponseVo submitOrderResponseVo=new SubmitOrderResponseVo();
        submitOrderResponseVo.setCode(0);
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
        //验证令牌,令牌的对比和删除必须保证原子性,返回0则校验失败
        String script="if redis.call('get',KEYS[1])==ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long executeResult = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class)
                , Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberRespVo
                        .getId()),
                vo.getOrderToken());
        if(executeResult==0)
        {
            submitOrderResponseVo.setCode(1);
        return submitOrderResponseVo;
        }
        else {
            //验证成功就去下单
            //创建订单，订单项等信息
            OrderCreateTo order = createOrder();
            BigDecimal payPrice = order.getPayPrice();
            BigDecimal payPrice1 = vo.getPayPrice();
            //验价，这里就不验价了，直接加个true
           if( true||Math.abs(payPrice.subtract(payPrice1).doubleValue())<0.01)
           {
                saveOrder(order);
                //生成订单之后去锁定库存,库存服务只要有异常，订单就取消
               WareSkuLockVo lockVo=new WareSkuLockVo();
               lockVo.setOrderSn(order.getOrder().getOrderSn());
               List<OrderItemEntity> orderItems = order.getOrderItems();
               List<OrderItemVo> collect = orderItems.stream().map(item -> {
                   OrderItemVo lockItemVo = new OrderItemVo();
                   lockItemVo.setSkuId(item.getSkuId());
                   lockItemVo.setCount(item.getSkuQuantity());
                   lockItemVo.setTitle(item.getSkuName());
                   return lockItemVo;
               }).collect(Collectors.toList());
               lockVo.setLocks(collect);
               //远程锁库存
               R r = wmsFeignService.orderLockStock(lockVo);
               if(r.getCode()==0){
                   //锁库存成功

                    submitOrderResponseVo.setOrder(order.getOrder());
                   int i=5/0;
                    return submitOrderResponseVo;
               }else {

                   //库存锁定失败，获取每一个的锁定结果
                   submitOrderResponseVo.setCode(3);
                   throw new NoStockException();
                  // return submitOrderResponseVo;
               }

           }
           else {
               submitOrderResponseVo.setCode(2);
               return submitOrderResponseVo;
           }

        }

    }

    /*
    * 按照订单号获取订单
    * */
    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        OrderEntity order_sn = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        return order_sn;
    }

    @Override
    public void close(OrderEntity entity) {

    }

    /*
    * 保存订单的所有数据
    * */

   private   void saveOrder(OrderCreateTo order) {
        OrderEntity orderEntity = order.getOrder();
        List<OrderItemEntity> orderItems = order.getOrderItems();
        orderEntity.setModifyTime(new Date());
        this.save(orderEntity);
        orderItemService.saveBatch(orderItems);
    }

    private OrderCreateTo createOrder(){
        OrderCreateTo orderCreateTo = new OrderCreateTo();
        //创建订单
        OrderEntity entity = bulidOrder();

        //订单号
        String timeId = IdWorker.getTimeId();
        entity.setOrderSn(timeId);
        //准备所有的订单项信息，获取购物车中的数据作为订单商品项目
        List<OrderItemEntity> orderItemEntities = bulidOrderItems(timeId);
        //验价
        computerPrice(entity,orderItemEntities);
        orderCreateTo.setOrder(entity);
        orderCreateTo.setOrderItems(orderItemEntities);
        return orderCreateTo;
    }

    private void computerPrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities) {

      BigDecimal total=new BigDecimal("0.0");
      BigDecimal coupon=new BigDecimal("0.0");
        BigDecimal integration=new BigDecimal("0.0");
        BigDecimal promotion=new BigDecimal("0.0");

        BigDecimal gift=new BigDecimal("0.0");
        BigDecimal growth=new BigDecimal("0.0");
        for (OrderItemEntity entity : orderItemEntities) {
            BigDecimal realAmount = entity.getRealAmount();
            BigDecimal couponAmount = entity.getCouponAmount();
            coupon= coupon.add(couponAmount);
            BigDecimal integrationAmount = entity.getIntegrationAmount();
            integration=   integration.add(integrationAmount);
            BigDecimal promotionAmount = entity.getPromotionAmount();
            promotion=  promotion.add(promotionAmount);
            total= total.add(realAmount);


            //积分成长值

            gift=gift.add(new BigDecimal(entity.getGiftIntegration().toString()));
            growth=growth.add(new BigDecimal(entity.getGiftGrowth().toString()));
        }
        //设置订单总额
        orderEntity.setTotalAmount(total);
        //加上运费，设置应付总额
        orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount()));
        orderEntity.setPromotionAmount(promotion);
        orderEntity.setCouponAmount(coupon);
        orderEntity.setIntegrationAmount(integration);
        //积分成长值
        orderEntity.setIntegration(gift.intValue());
        orderEntity.setGrowth(growth.intValue());
        //设置删除状态
        orderEntity.setDeleteStatus(0);

    }

    /*
    * 构建订单
    * */
    private OrderEntity bulidOrder() {
        OrderEntity entity=new OrderEntity();
        //设置会员信息
        MemberRespVo memberRespVo = LoginUserInterceptor.loginUser.get();
        entity.setMemberId(memberRespVo.getId());
        OrderSubmitVo orderSubmitVo = confirmVoThreadLocal.get();
        //设置运费
        entity.setFreightAmount(new BigDecimal("5.00"));
        //查询收货地址
        MemberReceiveAddressTo addrInfo = memberFeignService.getAddrInfo(orderSubmitVo.getAddrId());
        entity.setReceiverCity(addrInfo.getCity());
        entity.setReceiverDetailAddress(addrInfo.getDetailAddress());
        entity.setReceiverName(addrInfo.getName());
        entity.setReceiverPhone(addrInfo.getPhone());
        entity.setReceiverPostCode(addrInfo.getPostCode());
        entity.setReceiverProvince(addrInfo.getProvince());
        entity.setReceiverRegion(addrInfo.getRegion());
        //设置订单的状态
        entity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        entity.setAutoConfirmDay(15);

        return entity;
    }

    /*
    * 构建订单项
    * */
    private List<OrderItemEntity> bulidOrderItems(String orderSn) {
        List<OrderItemVo> currentUserCartItems = cartFeignService.getCurrentUserCartItems();
        if(currentUserCartItems!=null&&currentUserCartItems.size()>0)
        {
            List<OrderItemEntity> collect = currentUserCartItems.stream().map(cartItem -> {
                OrderItemEntity orderItemEntity = bulidOrderItem(cartItem);

                orderItemEntity.setOrderSn(orderSn);

                return orderItemEntity;
            }).collect(Collectors.toList());
            return collect;
        }

        return null;
    }
    /*
    * 构建某一个订单项
    * */
    private OrderItemEntity bulidOrderItem(OrderItemVo cartItem) {
        OrderItemEntity orderItemEntity=new OrderItemEntity();
        //spu
        R spuInfoBySkuId = productFeignService.getSpuInfoBySkuId(cartItem.getSkuId());
        SpuInfoVo spuInfoVo = spuInfoBySkuId.getData("data", new TypeReference<SpuInfoVo>() {
        });
         orderItemEntity.setSpuId(spuInfoVo.getId());
         orderItemEntity.setSpuBrand(spuInfoVo.getBrandId().toString());
         orderItemEntity.setSpuName(spuInfoVo.getSpuName());
         orderItemEntity.setCategoryId(spuInfoVo.getCatalogId());
        //sku
        orderItemEntity.setSkuId(cartItem.getSkuId());
        orderItemEntity.setSkuName(cartItem.getTitle());
        orderItemEntity.setSkuPic(cartItem.getImage());
        orderItemEntity.setSkuPrice(cartItem.getPrice());
        String skuAttr = StringUtils.collectionToDelimitedString(cartItem.getSkuAttr(), ";");
        orderItemEntity.setSkuAttrsVals(skuAttr);
        orderItemEntity.setSkuQuantity(cartItem.getCount());
        //积分
        orderItemEntity.setGiftGrowth(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount().toString())).intValue());
        orderItemEntity.setGiftIntegration(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount().toString())).intValue());
        //订单项的价格信息
        orderItemEntity.setPromotionAmount(new BigDecimal("0"));
        orderItemEntity.setCouponAmount(new BigDecimal("0"));
        orderItemEntity.setIntegrationAmount(new BigDecimal("0"));
        //当前订单项的实际金额，总额减去各种优惠
        BigDecimal orign = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()));
        BigDecimal subtract = orign.subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getPromotionAmount())
                .subtract(orderItemEntity.getIntegrationAmount());
        orderItemEntity.setRealAmount(subtract);
        return orderItemEntity;
    }

}